<?php

class User extends DBObject {

    public $table = 'sys.users';
    const table_static = 'sys.users';
    public $sequence = 'sys.users_id';
    const sequence_static = 'sys.users_id';

    public $_password;
    public $_email;
    public $_banned;
    public $_ban_reason;
    public $_registration_date;
    public $_registration_ip;
    public $_last_login;
    public $_access;
    public $_cookie;
    public $_picture_path;
    public $_lang;
    public $_select_lang;


    public static function getById($id) {

        return parent::getById($id, __CLASS__);
    }

    public static function getByName($name) {

        return parent::getByName($name, __CLASS__);
    }

    public function load() {

        parent::load();

        $res = $this->dbo->getRow("SELECT
            name,
            password,
            email,
            banned,
            ban_reason,
            registration_date,
            registration_ip,
            last_login,
            access,
            cookie,
            picture_path,
            lang,
            select_lang
            FROM $this->table
            WHERE id=?",
            array(
                DBInteger::create($this->id)
            ),
            DB_FETCHMODE_ASSOC
        );

        throwOnError($res);

        if(empty($res))
            throw new Exception('Failed to load user');

        $this->name = DBString::create($res['name']);
        $this->password = DBString::create($res['password']);
        $this->email = DBString::create($res['email']);
        $this->banned = DBBoolean::create($res['banned']);
        $this->ban_reason = DBBoolean::create($res['ban_reason']);
        $this->registration_date = DBString::create($res['registration_date']);
        $this->registration_ip = DBString::create($res['registration_ip']);
        $this->last_login = DBString::create($res['last_login']);
        $this->access = DBInteger::create($res['access']);
        $this->cookie = DBString::create($res['cookie']);
        $this->picture_path = DBString::create($res['picture_path']);
        $this->lang = DBString::create($res['lang']);
        $this->select_lang = DBBoolean::create($res['select_lang']);

        return true;
    }

    public function loadByName() {

        parent::loadByName();

        $res = $this->dbo->getRow("SELECT
            id,
            email,
            banned,
            ban_reason,
            registration_date,
            registration_ip,
            last_login,
            access,
            cookie,
            picture_path,
            lang,
            select_lang
            FROM $this->table
            WHERE LOWER(name)=LOWER(?) AND password=?",
            array(
                DBString::create($this->name),
                DBString::create($this->password)
            ),
            DB_FETCHMODE_ASSOC
        );

        throwOnError($res);

        if(empty($res))
            throw new Exception(_('Failed to load user.'));

        $this->id = DBInteger::create($res['id']);
        $this->email = DBString::create($res['email']);
        $this->banned = DBBoolean::create($res['banned']);
        $this->ban_reason = DBBoolean::create($res['ban_reason']);
        $this->registration_date = DBString::create($res['registration_date']);
        $this->registration_ip = DBString::create($res['registration_ip']);
        $this->last_login = DBString::create($res['last_login']);
        $this->access = DBInteger::create($res['access']);
        $this->cookie = DBString::create($res['cookie']);
        $this->picture_path = DBString::create($res['picture_path']);
        $this->lang = DBString::create($res['lang']);
        $this->select_lang = DBBoolean::create($res['select_lang']);

        return true;
    }

    public function __set($name, $value) {

        $value = trim($value);

        // validation
        switch($name) {
            case 'name':
                if(strlen($value) > MAX_USER_NAME_LENGTH)
                    throw new Exception(_('User name can be ').MAX_USER_NAME_LENGTH._(' characters max.'));

                if(strlen($value) < MIN_USER_NAME_LENGTH)
                    throw new Exception(_('User name must be ').MIN_USER_NAME_LENGTH.(' characters min.'));

                if(!preg_match('/^[a-zA-Z0-9\_\-]+$/', $value))
                    throw new Exception(_('User name: invalid characters.'));

                break;

            case 'password':
                if(strlen($value) > MAX_USER_PW_LENGTH)
                    throw new Exception(_('User password can be ').MAX_USER_PW_LENGTH._(' characters max.'));

                if(!preg_match('/^[a-zA-Z0-9\_\-]+$/', $value))
                    throw new Exception(_('User password: invalid characters.'));

                if(strlen($value) < MIN_USER_PW_LENGTH)
                    throw new Exception(_('User password must be ').MIN_USER_PW_LENGTH._(' characters min.'));

                break;

            case 'email':
                if(strlen($value) > MAX_USER_EMAIL_LENGTH)
                    throw new Exception(_('User email can be ').MAX_USER_EMAIL_LENGTH._(' characters max.'));

                if(strlen($value) > 0 && !filter_var($value, FILTER_VALIDATE_EMAIL))
                    throw new Exception(_('Invalid email: ') . $value);

                break;

            case 'banned':
                break;

            case 'ban_reason':
                if(strlen($value) > MAX_USER_BAN_REASON_LENGTH)
                    throw new Exception(_('Ban reason can be ').MAX_USER_BAN_REASON_LENGTH._(' characters max.'));

                break;

            case 'registration_date':
                break;

            case 'registration_ip':
                if(!filter_var($value, FILTER_VALIDATE_IP))
                    throw new Exception(_('Invalid ip: ') . $value);

                break;

            case 'last_login':
                break;

            case 'access':
                break;

            case 'lang':
                break;

            case 'select_lang':
                break;

        }
        parent::__set($name, $value);
    }

    public function __get($name) {

        return parent::__get($name);
    }

    public function save() {

       //if(!$this->changed && $this->loaded)
       //     return true;

        if(!is_null($this->id)) {

            $res = $this->dbo->query("UPDATE $this->table SET
                name=?,
                password=?,
                email=?,
                banned=?,
                ban_reason=?,
                registration_date=?,
                registration_ip=?,
                last_login=?,
                access=?,
                cookie=?,
                picture_path=?,
                lang=?,
                select_lang=?
                WHERE id=?",
                array(
                    DBString::create($this->name),
                    DBString::create($this->password),
                    DBString::create($this->email),
                    DBBoolean::create($this->banned),
                    DBString::create($this->ban_reason),
                    DBString::create($this->registration_date),
                    DBString::create($this->registration_ip),
                    DBString::create($this->last_login),
                    DBInteger::create($this->access),
                    DBString::create($this->cookie),
                    DBString::create($this->picture_path),
                    DBString::create($this->lang),
                    DBBoolean::create($this->select_lang),
                    DBInteger::create($this->id),
                    
                ));

            throwOnError($res);

            if($res != DB_OK)
                throw new Exception(_('Failed to save user.'));

        } else {

            eval("\$new_id = \$this->dbo->nextId(User::sequence_static);");

            $res = $this->dbo->query("INSERT INTO $this->table
                (id, name, password, email, banned,
                 ban_reason, registration_date, registration_ip,
                 last_login, access, cookie, picture_path, lang, select_lang) VALUES (?,?,?,?,?,?,?::timestamp,?,?,?,?,?,?,?)",
                array(
                    DBInteger::create($new_id),
                    DBString::create($this->name),
                    DBString::create($this->password),
                    DBString::create($this->email),
                    DBBoolean::create($this->banned),
                    DBString::create($this->ban_reason),
                    DBString::create($this->registration_date),
                    DBString::create($this->registration_ip),
                    DBString::create($this->last_login),
                    DBInteger::create($this->access),
                    DBString::create($this->cookie),
                    DBString::create($this->picture_path),
                    DBString::create($this->lang),
                    DBBoolean::create($this->select_lang)

                ));

            throwOnError($res);

            if($res != DB_OK)
                throw new Exception(_('Failed to save user.'));
        }

        return $this->id;
    }

    public function uploadPicture($file) {

        $picture_path = $this->name;
        $picture_path = str_replace(" ", "_", $picture_path);
        $picture_path = ereg_replace("[^A-Za-z0-9\_]", "", $picture_path);

        $db_path = '/'.USERPICS_THUMB_DIR . $picture_path;

        $picture_path = $_SERVER['DOCUMENT_ROOT'] . USERPICS_THUMB_DIR . $picture_path;

        $result_path = Picture::upload($file, $picture_path);

        Picture::generateThumbnail($result_path, USERPICS_THUMB_WIDTH, USERPICS_THUMB_HEIGHT);

        $this->picture_path = $db_path . '.' . end(explode('.', $result_path));

        $this->save();

        return true;
    }

    public function watchRelease($release_id) {

        $res = $this->dbo->query("SELECT mtl.watch_release(?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($release_id),
            ));

        throwOnError($res);

        return true;
    }

    public function unwatchRelease($release_id) {

        $res = $this->dbo->query("SELECT mtl.unwatch_release(?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($release_id),
            ));

        throwOnError($res);

        return true;
    }

    public function watchArtist($artist_id) {

        $res = $this->dbo->query("SELECT mtl.watch_artist(?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($artist_id),
            ));

        throwOnError($res);

        return true;
    }

    public function unwatchArtist($artist_id) {

        $res = $this->dbo->query("SELECT mtl.unwatch_artist(?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($artist_id),
            ));

        throwOnError($res);

        return true;
    }

    public function getWatchedReleases($filter = null) {

        if(empty($filter)) {
            $res = $this->dbo->getAll("SELECT *
                FROM mtl.watch_releases_view
                WHERE user_id = ?
                ORDER BY schedule_date ASC",
                array(
                    DBInteger::create($this->id)
                ),
                DB_FETCHMODE_ASSOC);
        } else {
            $res = $this->dbo->getAll("SELECT *
                FROM mtl.watch_releases_view
                WHERE user_id = ? AND genre ILIKE ?
                ORDER BY schedule_date ASC",
                array(
                    DBInteger::create($this->id),
                    DBString::create('%'.$filter.'%')
                ),
                DB_FETCHMODE_ASSOC);
        }

        throwOnError($res);

        return $res;
    }

    public function getWatchedArtists($filter = null) {

        if(empty($filter)) {
            $res = $this->dbo->getAll("SELECT *
                FROM mtl.watch_artists_view
                WHERE user_id = ?
                ORDER BY name ASC",
                array(
                    DBInteger::create($this->id)
                ),
                DB_FETCHMODE_ASSOC);
        } else {
            $res = $this->dbo->getAll("SELECT *
                FROM mtl.watch_artists_view
                WHERE user_id = ? AND genre ILIKE ?
                ORDER BY name ASC",
                array(
                    DBInteger::create($this->id),
                    DBString::create('%'.$filter.'%')
                ),
                DB_FETCHMODE_ASSOC);
        }

        throwOnError($res);

        return $res;
    }

    public static function create($name) {

        return parent::create($name, __CLASS__);
    }

    public static function exists($name) {

        return parent::exists($name, __CLASS__);
    }

    public static function emailExists($email) {

        $dbo = DBO::getInstance();
        // TODO: uncomment in PHP 5.3
        //$table_name = $class::table_static;
        eval("\$table_name = User::table_static;");
        $res = $dbo->getOne("SELECT COUNT(*)
            FROM $table_name
            WHERE LOWER(email) = LOWER(?)",
            array(
                DBString::create($email)
            ));

        throwOnError($res);

        return (boolean)($res > 0);
    }

    public static function getIdByCookie($cookie) {

        $dbo = DBO::getInstance();
        // TODO: uncomment in PHP 5.3
        //$table_name = $class::table_static;
        eval("\$table_name = User::table_static;");
        $res = $dbo->getOne("SELECT id
            FROM $table_name
            WHERE cookie = ?",
            array(
                DBString::create($cookie)
            ));

        throwOnError($res);

        if(empty($res))
            return false;

        return intval($res);
    }

    public static function getAnonymous() {

        $user = new self;

        $user->name = ANONYMOUS_USER_NAME;
        $user->access = 0;
        $user->id = 0;

        $auth = new Auth;
        $user->lang = $auth->getLangAuto();

        return $user;
    }
}